package com.example.feature.demo.util.redis.snowflake;

import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

/**
 * IdGrneratorFactory
 *
 * @author zhouxianfeng
 * @date 2021-5-13
 */
@Component
public class IdGrneratorFactory implements InitializingBean {

    private IdGenerator defaultIdGenerator;

    private Map<String, IdGenerator> generators = Maps.newConcurrentMap();

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private ReentrantLock reentrantLock = new ReentrantLock(true);

    @Value("${server.port:8080}")
    private String port;

    @Value("${spring.application.name:default}")
    private String name;

    private String key;

    public Long nextId() {
        return defaultIdGenerator.nextId();
    }

    public Long nextId(String business) {
        if (StringUtils.isEmpty(business)) {
            return defaultIdGenerator.nextId();
        }

        IdGenerator idGenerator = generators.get(business);
        if (idGenerator != null) {
            return idGenerator.nextId();
        } else {
            reentrantLock.lock();
            try {
                idGenerator = generators.get(business);
                if (idGenerator == null) {
                    IdGenerator idGeneratorNew = IdGenerator.getIdGeneratorNew(stringRedisTemplate, port, key, business);
                    generators.put(business, idGeneratorNew);
                    return idGeneratorNew.nextId();
                } else {
                    return idGenerator.nextId();
                }
            } finally {
                reentrantLock.unlock();
            }

        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        key = name + ":" + "idGenerator";
        defaultIdGenerator = IdGenerator.getIdGeneratorNew(stringRedisTemplate, port, key, null);
    }
}
